using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Services;
using Sudoku.Menu;
using System.Diagnostics;


namespace Sudoku.GamePlay
{
	public class BoardRenderer : ExtendedGameComponent
	{

		private Vector2 origin = new Vector2(16, 27);
		private Vector2 padOrigin = new Vector2(130, 495);

		private List<NumberButton> numberButtons;
		private List<List<CellButton>> cellButtons;

		private bool guessMode = false;

		private Button erase;
		private Button guess;

		private Texture2D bg;

		private Point selectionIndex = new Point(0, 0);
		private CellButton selectedCellButton;

		private Rectangle row;
		private Rectangle col;
		private Rectangle square;
		private Texture2D selTexture;
		private Color selColor;

		public BoardRenderer(Game game)
			: base(game)
		{
			UpdateOrder = (int)ComponentOrders.RENDERER;
			DrawOrder = (int)ComponentOrders.RENDERER;

			boardService = Game.Services.GetService(typeof(IBoard)) as IBoard;
		}

		IBoard boardService;
		CellButton lastCellButton;

		public override void Initialize()
		{
			soundService.TurnPageSound();

			numberButtons = new List<NumberButton>();
			cellButtons = new List<List<CellButton>>();

			for (int y = 0; y < 9; ++y)
			{
				List<CellButton> row = new List<CellButton>();

				for (int x = 0; x < 9; ++x)
				{
					CellButton button = new CellButton(Game, boardService.GetCell(x, y), new Rectangle((int)origin.X + 50 * x, (int)origin.Y + 50 * y, 50, 50));
					button.Texture = textureService.Texture("Numbers");
					button.OnTap += new Button.ButtonEvent(OnCellButton);
					button.IsToggle = true;
					row.Add(button);
					this.Components.Add(button);
				}

				cellButtons.Add(row);

				NumberButton nButton = new NumberButton(Game, new Rectangle( (int) padOrigin.X + 55 * (y % 3), (int) padOrigin.Y + 55 * (y / 3), 55, 55), (byte)(y + 1));
				nButton.Texture = textureService.Texture("Numbers");
				nButton.OnTap += new Button.ButtonEvent(OnNumberButton);
				this.Components.Add(nButton);
				numberButtons.Add(nButton);
			}
			
			guess = new Button(Game, new Rectangle((int)padOrigin.X + 165, (int)padOrigin.Y, 55, 83));
			guess.Texture = textureService.Texture("Guess");
			guess.IsToggle = true;
			guess.DownColor = Color.Pink;
			guess.OnTap += new Button.ButtonEvent(OnGuessButton);
			this.Components.Add(guess);

			erase = new Button(Game, new Rectangle((int)padOrigin.X + 170, (int)padOrigin.Y + 100, 45, 42));
			erase.Texture = textureService.Texture("Eraser");
			erase.DownColor = Color.Pink;
			erase.OnTap += new Button.ButtonEvent(OnEraserSelect);
			this.Components.Add(erase);

			bg = textureService.Background("Sudoku");
			selTexture = textureService.Texture("WhiteFill");
			selColor = Color.Pink;
			selColor.A = 50;

			// Register for keyboard input
			IInputManager inputService = (IInputManager)Game.Services.GetService(typeof(IInputManager));
			inputService.OnKeyDown += new InputManager.KeyboardEvent(OnKeyDown);
			inputService.OnKeyUp += new InputManager.KeyboardEvent(OnKeyUp);
			base.Initialize();
		}

		#region INPUT

		private void OnCellButton(Button sender)
		{

			if (lastCellButton != null && lastCellButton == sender)
			{

				boardService.SetSelectedCell(null);
				lastCellButton = null;
				return;
			}
			else
			{

				if (lastCellButton != null && lastCellButton != sender)
					lastCellButton.State = Menu.ButtonState.NORMAL;

				lastCellButton = sender as CellButton;

				boardService.SetSelectedCell(lastCellButton.BoardCell);

				if (guessMode)
				{
					for (int i = 0; i < 9; ++i)
					{
						if (boardService.GetSelectedCell() != null && boardService.GetSelectedCell().Guess[i])
							numberButtons[i].State = Menu.ButtonState.DOWN;
						else
							numberButtons[i].State = Menu.ButtonState.NORMAL;
					}
				}

				//create rectangle for visual effect
				Rectangle pos = lastCellButton.Position;
				row = new Rectangle((int)origin.X, (int)pos.Y, 450, 50);
				col = new Rectangle((int)pos.X, (int)origin.Y, 50, 450);
				Vector2 diff = new Vector2(pos.X - origin.X, pos.Y - origin.Y);
				int x = (int)diff.X / 150;
				int y = (int)diff.Y / 150;
				square = new Rectangle((int)origin.X + 150 * x, (int)origin.Y + 150 * y, 150, 150);

				selectionIndex.X = (int)diff.X / 50;
				selectionIndex.Y = (int)diff.Y / 50;

				// Disable some buttons if the lastcell is fixed
				foreach (NumberButton b in numberButtons)
					b.Enabled = !lastCellButton.BoardCell.Fixed;

				erase.Enabled = !lastCellButton.BoardCell.Fixed;
				guess.Enabled = !lastCellButton.BoardCell.Fixed;
			}
		}

		private void OnGuessButton(Button sender)
		{
			if (guessMode)
			{
				for (int i = 0; i < 9; ++i)
				{
					numberButtons[i].IsToggle = false;
					numberButtons[i].State = Menu.ButtonState.NORMAL;
				}
				guessMode = false;
			}
			else
			{
				if (lastCellButton == null)
				{
					sender.State = Menu.ButtonState.NORMAL;
					return;
				}

				if (lastCellButton.BoardCell.Fixed)
				{
					sender.State = Menu.ButtonState.NORMAL;
					return;
				}

				for (int i = 0; i < 9; ++i)
				{
					numberButtons[i].IsToggle = true;
                    if (boardService.GetSelectedCell() != null && boardService.GetSelectedCell().Guess[i])
                    {
                        numberButtons[i].State = Menu.ButtonState.DOWN;
                        numberButtons[i].IsToggleDown = boardService.GetSelectedCell().Guess[i];
                    }
				}
				guessMode = true;
			}
		}

		private void OnNumberButton(Button sender)
		{
			if (!guessMode) boardService.SetSelectedCellValue(((NumberButton)sender).Value);
			else boardService.SetSelectedCellGuess(((NumberButton)sender).Value - 1);
		}

		private void OnEraserSelect(Button sender)
		{
			boardService.SetSelectedCellValue( 0 );
		}

		#endregion

		#region KEYBOARD INPUT

		private void OnKeyDown(Keys key)
		{

			switch (key)
			{
				case Keys.D0: erase.Hold(); break;
				case Keys.D1: numberButtons[0].Hold(); break;
				case Keys.D2: numberButtons[1].Hold(); break;
				case Keys.D3: numberButtons[2].Hold(); break;
				case Keys.D4: numberButtons[3].Hold(); break;
				case Keys.D5: numberButtons[4].Hold(); break;
				case Keys.D6: numberButtons[5].Hold(); break;
				case Keys.D7: numberButtons[6].Hold(); break;
				case Keys.D8: numberButtons[7].Hold(); break;
				case Keys.D9: numberButtons[8].Hold(); break;

				case Keys.G: guess.Tap(); break;
				case Keys.Space: erase.Tap(); break;
			}
		}

		private void OnKeyUp(Keys key)
		{
			switch (key)
			{
				case Keys.D0: erase.Tap(); break;
				case Keys.D1: numberButtons[0].Tap(); break;
				case Keys.D2: numberButtons[1].Tap(); break;
				case Keys.D3: numberButtons[2].Tap(); break;
				case Keys.D4: numberButtons[3].Tap(); break;
				case Keys.D5: numberButtons[4].Tap(); break;
				case Keys.D6: numberButtons[5].Tap(); break;
				case Keys.D7: numberButtons[6].Tap(); break;
				case Keys.D8: numberButtons[7].Tap(); break;
				case Keys.D9: numberButtons[8].Tap(); break;

				case Keys.G: guess.Tap(); break;
				case Keys.Space: erase.Tap(); break;

				case Keys.Left: selectionIndex.X = selectionIndex.X > 0 ? --selectionIndex.X : 0; break;
				case Keys.Right: selectionIndex.X = selectionIndex.X < 8 ? ++selectionIndex.X : 8; break;
				case Keys.Up: selectionIndex.Y = selectionIndex.Y > 0 ? --selectionIndex.Y : 0; break;
				case Keys.Down: selectionIndex.Y = selectionIndex.Y < 8 ? ++selectionIndex.Y : 8; break;
			}

			if (selectedCellButton != null)
				selectedCellButton.Tap();

			selectedCellButton = cellButtons[selectionIndex.Y][selectionIndex.X];
			selectedCellButton.Tap();
			boardService.SetSelectedCell(selectedCellButton.BoardCell);
		}

		#endregion

		public override void Draw(GameTime gameTime)
		{
			spriteBatch.Begin();

			spriteBatch.Draw(bg, new Rectangle(0,0,GraphicsDevice.Viewport.Width,GraphicsDevice.Viewport.Height), Color.White);
			
			spriteBatch.End();
			
			spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.NonPremultiplied);
				
			if (lastCellButton != null)
			{
				spriteBatch.Draw(selTexture, row, selColor);
				spriteBatch.Draw(selTexture, col, selColor);
				spriteBatch.Draw(selTexture, square, selColor);
			}

			spriteBatch.End();
			
			base.Draw(gameTime);
		}
	}
}
